/*
Copyright [2020] [https://www.stylefeng.cn]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Guns采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Guns源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/stylefeng/guns-separation
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/stylefeng/guns-separation
6.若您的项目无法满足以上几点，可申请商业授权，获取Guns商业授权许可，请在官网购买授权，地址为 https://www.stylefeng.cn
 */
package cn.stylefeng.guns.sys.modular.auth.controller;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.guns.core.context.login.LoginContextHolder;
import cn.stylefeng.guns.core.pojo.login.SysLoginUser;
import cn.stylefeng.guns.core.pojo.response.ResponseData;
import cn.stylefeng.guns.core.pojo.response.SuccessResponseData;
import cn.stylefeng.guns.sys.core.enums.PublicEnum;
import cn.stylefeng.guns.sys.modular.auth.service.AuthService;
import cn.stylefeng.guns.sys.modular.user.entity.EnterpriseUserMsg;
import cn.stylefeng.guns.sys.modular.user.entity.SysTenant;
import cn.stylefeng.guns.sys.modular.user.entity.SysUser;
import cn.stylefeng.guns.sys.modular.user.mapper.EnterpriseUserMsgMapper;
import cn.stylefeng.guns.sys.modular.user.param.SysUserEditPassword;
import cn.stylefeng.guns.sys.modular.user.param.SysUserParam;
import cn.stylefeng.guns.sys.modular.user.param.SysUserUpdatePassword;
import cn.stylefeng.guns.sys.modular.user.service.SysTenantService;
import cn.stylefeng.guns.sys.modular.user.service.SysUserService;
import cn.stylefeng.guns.sys.modular.util.FuseCloudSmsUtil;
import cn.stylefeng.guns.sys.modular.util.ImgVerifyCode;
import cn.stylefeng.guns.sys.modular.util.RandomStringUtils;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.awt.image.BufferedImage;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 登录控制器
 *
 * @author xuyuxiang
 * @date 2020/3/11 12:20
 */
@RestController
public class SysLoginController {


    @Resource
    private AuthService authService;
    @Autowired
    private FuseCloudSmsUtil fuseCloudSmsUtil;
    @Autowired
    private SysTenantService sysTenantService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private EnterpriseUserMsgMapper enterpriseUserMsgMapper;


    /**
     * 账号密码登录
     *
     * @author xuyuxiang
     * @date 2020/3/11 15:52
     */
    @PostMapping("/login")
    public ResponseData login(@RequestBody Dict dict) {
        String account = dict.getStr("account");
        String password = dict.getStr("password");
        String clientId = dict.getStr("clientId");
        String type = dict.getStr("type");
        // Long tenantId = StrUtil.isNotBlank(dict.getStr("tenantId")) ? Long.valueOf(dict.getStr("tenantId")) : null;

        Object token = authService.login(account, password, null, clientId, type);

        return new SuccessResponseData(token);
    }

    @PostMapping("/getAccount")
    public ResponseData getAccount() {
        Long tenantId = LoginContextHolder.me().getSysLoginUser().getTenantId();
        String name = "";
        if (LoginContextHolder.me().isSuperAdmin()) {
            name = "平台管理账号";
        } else {
            SysTenant sysTenant = sysTenantService.getById(tenantId);
            name = sysTenant.getName();

            //如果名字超过四位则截取前四位
            if (name.length() > 4) {
                name = name.substring(0, 4);
            }
        }
        //获取用户数量
        //int count = sysUserService.count(new QueryWrapper<SysUser>().lambda().eq(SysUser::getTenantId, tenantId));
        //String format = String.format("%06d", count);
        return new SuccessResponseData(name);
    }


    /**
     * 账号密码登录
     *
     * @author xuyuxiang
     * @date 2020/3/11 15:52
     */
    /*@PostMapping("/wx/login")
    public ResponseData login(@RequestBody SysUser sysUser) {
        Object token = null;
        // 如果前端没有传手机号
        if (StringUtils.isEmpty(sysUser.getPhone())) {
            // 根据openId去数据库中查询用户信息，且用户状态是正常
            SysUser user = sysUserService.getOne(new QueryWrapper<SysUser>().lambda()
                    .eq(SysUser::getWechatOpenid, sysUser.getWechatOpenid())
                    .eq(SysUser::getStatus, PublicEnum.ROLE_STATE));

            // 如果没有查询到用户则返回错误提示
            if (user == null) {
                return ResponseData.error("未绑定手机号,请先绑定手机号");
            } else {
                // 如果查询到用户调用wxLogin方法获取token
                token = authService.wxLogin(user.getAccount(), null, sysUser.getClientId(), "1");
            }
        } else {

            Object codeObj = redisTemplate.opsForValue().get("wx_code_" + sysUser.getPhone());
            //忘记密码短信验证
            if (codeObj == null) {
                return ResponseData.error("请先获取验证码");
            }
            String code = codeObj.toString();
            if (!StrUtil.equals(code, sysUser.getCaptcha())) {
                return ResponseData.error("验证码错误");
            }
            //查询手机号是否已存在
            SysUser user = sysUserService.getOne(new QueryWrapper<SysUser>().lambda()
                    .eq(SysUser::getPhone, sysUser.getPhone())
                    .eq(SysUser::getStatus, PublicEnum.ROLE_STATE));
            if (user != null) {
                //存在,保存微信id并登录
                SysUser newUser = new SysUser();
                newUser.setWechatOpenid(sysUser.getWechatOpenid());
                newUser.setId(user.getId());
                sysUserService.updateById(newUser);
                //根据openid获取用户
                token = authService.wxLogin(user.getAccount(), null, sysUser.getClientId(), "1");
            } else {
                //不存在,注册并登录
                SysUserParam param = new SysUserParam();
                param.setPhone(sysUser.getPhone())
                        .setPassword("123456")
                        .setWechatOpenid(sysUser.getWechatOpenid());
                authService.register(param);
                //根据openid获取用户
                token = authService.wxLogin(sysUser.getAccount(), null, sysUser.getClientId(), "1");
            }
        }
        return new SuccessResponseData(token);
    }*/
    @PostMapping("/thirdParty/login")
    public ResponseData login(@RequestBody SysUser sysUser) {
        // 获取当前登录类型，1微信 2苹果
        String loginType = sysUser.getLoginType();
        if (org.springframework.util.StringUtils.isEmpty(loginType)) {
            return ResponseData.error("登录类型参数未传！");
        }

        Object token = null;
        // 如果前端没有传手机号
        if (StringUtils.isEmpty(sysUser.getPhone())) {
            // 根据openId去数据库中查询用户信息，且用户状态是正常
            SysUser user = null;
            if ("1".equals(loginType)) {
                user = sysUserService.getOne(new QueryWrapper<SysUser>().lambda()
                        .eq(SysUser::getWechatOpenid, sysUser.getWechatOpenid())
                        .eq(SysUser::getStatus, PublicEnum.ROLE_STATE));
            } else if ("2".equals(loginType)) {
                user = sysUserService.getOne(new QueryWrapper<SysUser>().lambda()
                        .eq(SysUser::getAppleOpenid, sysUser.getAppleOpenid())
                        .eq(SysUser::getStatus, PublicEnum.ROLE_STATE));
            }
            // 如果没有查询到用户则返回错误提示
            if (user == null) {
                return ResponseData.error("未绑定手机号,请先绑定手机号");
            } else {
                token = authService.thirdPartyLogin(user.getAccount(), null, sysUser.getClientId(), "1");
            }
        } else {
            Object codeObj = null;
            if ("1".equals(loginType)) {
                codeObj = redisTemplate.opsForValue().get("wx_code_" + sysUser.getPhone());
            } else if ("2".equals(loginType)) {
                codeObj = redisTemplate.opsForValue().get("apple_code_" + sysUser.getPhone());
            }
            //忘记密码短信验证
            if (codeObj == null) {
                return ResponseData.error("请先获取验证码");
            }
            String code = codeObj.toString();
            if (!StrUtil.equals(code, sysUser.getCaptcha())) {
                return ResponseData.error("验证码错误");
            }
            //查询手机号是否已存在
            SysUser user = sysUserService.getOne(new QueryWrapper<SysUser>().lambda()
                    .eq(SysUser::getPhone, sysUser.getPhone())
                    .eq(SysUser::getStatus, PublicEnum.ROLE_STATE)
                    .eq(SysUser::getTenantId, -1));
            if (user != null) {
                //存在,保存微信/苹果id并登录
                SysUser newUser = new SysUser();
                if ("1".equals(loginType)) {
                    newUser.setWechatOpenid(sysUser.getWechatOpenid());
                } else {
                    newUser.setAppleOpenid(sysUser.getAppleOpenid());
                }
                newUser.setId(user.getId());
                sysUserService.updateById(newUser);
                //根据openid获取用户
                token = authService.thirdPartyLogin(user.getAccount(), null, sysUser.getClientId(), "1");
            } else {
                //不存在,注册并登录
                SysUserParam param = new SysUserParam();
                String password = sysUser.getPassword();
                if (org.springframework.util.StringUtils.isEmpty(password)) {
                    password = "123456";
                }
                param.setPhone(sysUser.getPhone())
                        .setPassword(password).setLoginType(sysUser.getLoginType());
                if ("1".equals(loginType)) {
                    param.setWechatOpenid(sysUser.getWechatOpenid());
                } else {
                    param.setAppleOpenid(sysUser.getAppleOpenid());
                }
                authService.register(param);
                //根据openid获取用户
                token = authService.thirdPartyLogin(sysUser.getPhone(), null, sysUser.getClientId(), "1");
            }
        }
        return new SuccessResponseData(token);
    }

    @RequestMapping(value = "/forgetPwd", method = RequestMethod.POST)
    @ApiOperation(value = "忘记密码")
    public ResponseData forgetPwd(@RequestBody @Valid SysUserUpdatePassword req) {
        Object codeObj = redisTemplate.opsForValue().get("forget_code_" + req.getAccount());
        //忘记密码短信验证
        if (codeObj == null) {
            return ResponseData.error("请先获取验证码");
        }
        String code = codeObj.toString();
        if (!StrUtil.equals(code, req.getCaptcha())) {
            return ResponseData.error("验证码错误");
        }
        return authService.forgetPwd(req);
    }


    @RequestMapping(value = "/editPwd", method = RequestMethod.POST)
    @ApiOperation(value = "修改密码")
    public ResponseData editPwd(@RequestBody @Valid SysUserEditPassword req) {
        return authService.editPwd(req, LoginContextHolder.me().getSysLoginUserId());
    }


    @PostMapping("/register")
    @ApiOperation(value = "APP注册新用户", notes = "H5/APP注册新用户")
    public ResponseData<String> register(@Validated @RequestBody SysUserParam param) {

        Object codeObj = redisTemplate.opsForValue().get("code_" + param.getPhone());
        //忘记密码短信验证
        if (codeObj == null) {
            return ResponseData.error("请先获取验证码");
        }
        String code = codeObj.toString();
        if (!StrUtil.equals(code, param.getCaptcha())) {
            return ResponseData.error("验证码错误");
        }
        SysUser yxUser = sysUserService.getOne(Wrappers.<SysUser>lambdaQuery()
                        .eq(SysUser::getAccount, param.getPhone())
                        .eq(SysUser::getStatus, PublicEnum.ROLE_STATE.getCode())
                , false);
        if (ObjectUtil.isNotNull(yxUser)) {
            return ResponseData.error("用户已存在");
        }
        return authService.register(param);
    }


    @PostMapping("/register/verify")
    @ApiOperation(value = "短信验证码发送", notes = "短信验证码发送")
    public ResponseData<String> verify(@Validated @RequestBody SysUserParam param) {
        String key = param.getKey();
        String imageCaptcha = param.getImageCaptcha();
        // 获取注册短信时,先校验图形验证码
        Object value = redisTemplate.opsForValue().get(key);
        if (value != null) {
            if (StrUtil.isBlankOrUndefined(value.toString())) {
                return ResponseData.error("请先获取图形验证码");
            }
            if (!StrUtil.equalsIgnoreCase(value.toString(), imageCaptcha)) {
                return ResponseData.error("图形验证码错误");
            }
        } else {
            return ResponseData.error("请先获取图形验证码");
        }


        String codeKey = "";
        //注册短信验证
        if (param.getType() == 1) {
            codeKey = "code_" + param.getPhone();
            //忘记密码短信验证
        } else if (param.getType() == 2) {
            codeKey = "forget_code_" + param.getPhone();
            //微信绑定手机号
        } else if (param.getType() == 3) {
            codeKey = "wx_code_" + param.getPhone();
        } else if (param.getType() == 4) {
            //苹果绑定手机号
            codeKey = "apple_code_" + param.getPhone();
        }

        String code = RandomStringUtils.randomStr();


        //redis存储
        redisTemplate.opsForValue().set(codeKey, code, 600L, TimeUnit.SECONDS);
        //生成随机验证码

        //发送助通短信
        try {
            //fuseCloudSmsUtil.sendSms(param.getPhone(), code);
            String codeResult = fuseCloudSmsUtil.sendSms(param.getPhone().toString(), "【运车宝】您的验证码是" + code + " 如非本人操作，请忽略本短信!");
            Map map = JSONObject.parseObject(codeResult, Map.class);
            //判断短信是否发送成功
            if (StringUtils.isNotEmpty(codeResult) && map.get("msg").equals("success")) {
                return ResponseData.success(null);
            }
        } catch (Exception e) {
            redisTemplate.delete(codeKey);
            e.printStackTrace();
            return ResponseData.error("发送失败");
        }
        return ResponseData.success("发送成功，请注意查收");


    }


    @RequestMapping(value = "/captcha", method = RequestMethod.POST)
    public void appCaptcha(HttpServletResponse response,
                           @RequestBody @NotNull(message = "key不能为空") String key) throws Exception {
        ImgVerifyCode ivc = new ImgVerifyCode();     //使用验证码类，生成验证码类对象
        BufferedImage image = ivc.getImage();  //获取验证码
        ivc.output(image, response.getOutputStream());//将验证码图片响应给客户端
        redisTemplate.opsForValue().set(key, ivc.getText(), 3, TimeUnit.MINUTES);
    }


    /**
     * 退出登录
     *
     * @author xuyuxiang
     * @date 2020/3/16 15:02
     */
    @GetMapping("/logout")
    public ResponseData logout() {
        authService.logout();
        return new SuccessResponseData();
    }

    /**
     * 获取当前登录用户信息
     *
     * @author xuyuxiang, fengshuonan
     * @date 2020/3/23 17:57
     */
    @PostMapping("/getLoginUser")
    public ResponseData getLoginUser() {
        SysLoginUser user = LoginContextHolder.me().getSysLoginUserUpToDate();
        Long tenantId = user.getTenantId();
        EnterpriseUserMsg enterpriseUserMsg = enterpriseUserMsgMapper.selectOne(new LambdaQueryWrapper<EnterpriseUserMsg>()
                .eq(EnterpriseUserMsg::getTenantId, tenantId));
        if (enterpriseUserMsg != null) {
            user.setIsOpen("1");
        } else {
            user.setIsOpen("2");
        }
        return new SuccessResponseData(user);
    }


    /**
     * 获取当前登录用户信息
     *
     * @author xuyuxiang, fengshuonan
     * @date 2020/3/23 17:57
     */
    @PostMapping("/getOrgList")
    public ResponseData getOrgList() {
        return new SuccessResponseData(authService.getUserOrgList(LoginContextHolder.me().getSysLoginUserId()));
    }
}
